// Copyright 2022 AndeyaLee. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package core

import (
	"bytes"
	"net/http"
	"sync"
)

// ContextPool manages a pool of Context objects to reduce GC pressure
var ContextPool = sync.Pool{
	New: func() interface{} {
		return &Context{}
	},
}

// GetContext retrieves a Context from the pool
func GetContext() *Context {
	ctx := ContextPool.Get().(*Context)
	ctx.Reset()
	return ctx
}

// PutContext returns a Context to the pool
func PutContext(ctx *Context) {
	ContextPool.Put(ctx)
}

// BufferPool manages a pool of bytes.Buffer objects
var BufferPool = sync.Pool{
	New: func() interface{} {
		return &bytes.Buffer{}
	},
}

// GetBuffer retrieves a bytes.Buffer from the pool
func GetBuffer() *bytes.Buffer {
	buf := BufferPool.Get().(*bytes.Buffer)
	buf.Reset()
	return buf
}

// PutBuffer returns a bytes.Buffer to the pool
func PutBuffer(buf *bytes.Buffer) {
	BufferPool.Put(buf)
}

// PathParamsPool manages a pool of PathParams slices
var PathParamsPool = sync.Pool{
	New: func() interface{} {
		return make(PathParams, 0, 8) // Pre-allocate capacity for 8 params
	},
}

// GetPathParams retrieves a PathParams slice from the pool
func GetPathParams() PathParams {
	params := PathParamsPool.Get().(PathParams)
	return params[:0] // Reset length but keep capacity
}

// PutPathParams returns a PathParams slice to the pool
func PutPathParams(params PathParams) {
	PathParamsPool.Put(params)
}

// HandlerChainPool manages a pool of HandlerChain slices
var HandlerChainPool = sync.Pool{
	New: func() interface{} {
		return make(HandlerChain, 0, 4) // Pre-allocate capacity for 4 handlers
	},
}

// GetHandlerChain retrieves a HandlerChain slice from the pool
func GetHandlerChain() HandlerChain {
	chain := HandlerChainPool.Get().(HandlerChain)
	return chain[:0] // Reset length but keep capacity
}

// PutHandlerChain returns a HandlerChain slice to the pool
func PutHandlerChain(chain HandlerChain) {
	HandlerChainPool.Put(chain)
}

// StringSlicePool manages a pool of string slices
var StringSlicePool = sync.Pool{
	New: func() interface{} {
		return make([]string, 0, 8) // Pre-allocate capacity for 8 strings
	},
}

// GetStringSlice retrieves a string slice from the pool
func GetStringSlice() []string {
	slice := StringSlicePool.Get().([]string)
	return slice[:0] // Reset length but keep capacity
}

// PutStringSlice returns a string slice to the pool
func PutStringSlice(slice []string) {
	StringSlicePool.Put(slice)
}

// MapPool manages a pool of map[string]interface{} objects
var MapPool = sync.Pool{
	New: func() interface{} {
		return make(map[string]interface{}, 8) // Pre-allocate capacity for 8 entries
	},
}

// GetMap retrieves a map from the pool
func GetMap() map[string]interface{} {
	m := MapPool.Get().(map[string]interface{})
	// Clear the map
	for k := range m {
		delete(m, k)
	}
	return m
}

// PutMap returns a map to the pool
func PutMap(m map[string]interface{}) {
	MapPool.Put(m)
}

// RequestPool manages a pool of request objects for reuse
var RequestPool = sync.Pool{
	New: func() interface{} {
		return &http.Request{}
	},
}

// GetRequest retrieves a Request from the pool
func GetRequest() *http.Request {
	req := RequestPool.Get().(*http.Request)
	// Reset request fields manually since we can't define methods on http.Request
	req.Method = ""
	req.URL = nil
	req.Header = nil
	req.Body = nil
	req.RemoteAddr = ""
	req.RequestURI = ""
	req.Proto = ""
	req.ProtoMajor = 0
	req.ProtoMinor = 0
	req.ContentLength = 0
	req.TransferEncoding = nil
	req.Close = false
	req.Host = ""
	req.Form = nil
	req.PostForm = nil
	req.MultipartForm = nil
	req.Trailer = nil
	req.TLS = nil
	req.Cancel = nil
	req.Response = nil
	return req
}

// PutRequest returns a Request to the pool
func PutRequest(req *http.Request) {
	RequestPool.Put(req)
}

// ResponsePool manages a pool of Response objects for reuse
var ResponsePool = sync.Pool{
	New: func() interface{} {
		return &Response{}
	},
}

// GetResponse retrieves a Response from the pool
func GetResponse() *Response {
	resp := ResponsePool.Get().(*Response)
	resp.Reset()
	return resp
}

// PutResponse returns a Response to the pool
func PutResponse(resp *Response) {
	ResponsePool.Put(resp)
}

// NodePool manages a pool of tree nodes for reuse
var NodePool = sync.Pool{
	New: func() interface{} {
		return &node{}
	},
}

// GetNode retrieves a node from the pool
func GetNode() *node {
	n := NodePool.Get().(*node)
	n.Reset()
	return n
}

// PutNode returns a node to the pool
func PutNode(n *node) {
	NodePool.Put(n)
}

// Reset resets a node to its zero state
func (n *node) Reset() {
	n.path = ""
	n.indices = ""
	n.children = nil
	n.handle = nil
	n.priority = 0
	n.nType = static
	n.maxParams = 0
	n.wildChild = false
}

// Reset resets a Context to its zero state
func (c *Context) Reset() {
	c.R = nil
	c.W = nil
	c.curSession = nil
	c.limitedRequestBody = nil
	c.frame = nil
	c.handlerChain = nil
	c.pathParams = nil
	c.queryParams = nil
	c.data = nil
	c.handlerChainLen = 0
	c.pos = 0
	c.enableGzip = false
	c.enableSession = false
	c.enableXSRF = false
	c.xsrfExpire = 0
	c._xsrfToken = ""
	c._xsrfTokenReset = false
}

// Reset resets a Response to its zero state
func (r *Response) Reset() {
	r.status = 0
	r.size = 0
	r.committed = false
	r.writer = nil
	r.context = nil
}
